<template>
  <div class="ui-form">
    <!-- 表单 -->
    <el-form :model="uiFormData" v-bind="mergedFormAttributes" ref="formRef">
      <!-- 栅格 行 -->
      <el-row v-bind="mergedRowLayout" class="row">
        <!-- 表单循环选项 -->
        <template v-for="(item, index) in mergedFormItems" :key="index">
          <!-- 栅格 列 -->
          <el-col v-bind="item.colLayout" v-if="item.show">
            <!-- slot 类型单独处理 -->
            <el-form-item v-if="item.type !== 'slot'" :prop="item.field" :label="item.label" :rules="item.rules">
              <!-- input、password 组件 -->
              <template v-if="item.type === 'input' || item.type === 'password'">
                <el-input v-model="uiFormData[item.field]" v-bind="item.attributes"
                  @input="formItemChange($event, item)"></el-input>
              </template>

              <!-- select 组件 -->
              <template v-if="item.type === 'select'">
                <el-select v-model="uiFormData[item.field]" v-bind="item.attributes"
                  @change="formItemChange($event, item)">
                  <el-option v-for="option in item.options" :key="option.value" :value="option.value"
                    :label="option.label"></el-option>
                </el-select>
              </template>

              <!-- date、datePicker、dateRange -->
              <template v-if="item.type === 'date' || item.type === 'datePicker' || item.type === 'dateRange'">
                <el-date-picker v-model="uiFormData[item.field]" v-bind="item.attributes"
                  @change="formItemChange($event, item)"></el-date-picker>
              </template>

              <!-- inputNumber -->
              <template v-if="item.type === 'inputNumber'">
                <el-input-number v-model="uiFormData[item.field]" v-bind="item.attributes"
                  @input="formItemChange($event, item)" />
              </template>

              <!-- radio -->
              <template v-if="item.type === 'radio'">
                <el-radio-group v-model="uiFormData[item.field]" v-bind="item.attributes"
                  @change="formItemChange($event, item)">
                  <el-radio v-for="option in item.options" :key="option.value" :value="option.value">
                    {{ option.label }}
                  </el-radio>
                </el-radio-group>
              </template>
            </el-form-item>

            <!-- 可自定义 slot -->
            <el-form-item v-if="item.type === 'custom-slot'" label="" label-width="0">
              <slot name="custom-slot"></slot>
            </el-form-item>
          </el-col>
        </template>
      </el-row>
    </el-form>
  </div>
</template>

<script setup lang="js">
import { ref, watch, computed } from "vue";

const emit = defineEmits(["update:formData", "handleFormItemChange"]);

const props = defineProps({
  // 组件接收表单数据
  formData: {
    type: Object,
    required: true
  },
  // 表单所有配置选项数据
  formItems: {
    type: Array,
    default: () => []
  },
  // el-form api 属性
  formAttributes: {
    type: Object,
    default: () => ({})
  },
  // el-row api 属性
  rowLayout: {
    type: Object,
    default: () => ({})
  }
});

// 解决 v-bind 不能初始化值formAttributes
const mergedFormAttributes = computed(() => ({
  labelWidth: "68px",
  disabled: false,     // 默认不禁用
  ...props.formAttributes
}));

// 解决 v-bind 不能初始化值rowLayout
const mergedRowLayout = computed(() => ({
  gutter: 10,
  ...props.rowLayout
}));

// 解决 v-bind 不能初始化值formItems
const mergedFormItems = computed(() =>
  props.formItems.map((item) => ({
    show: true, // 默认显示
    ...item,
    attributes: {
      disabled: false, // 默认可编辑
      ...(item.attributes || {})
    },
    rules: item.rules || [], // 外部传了就用外部的
    colLayout: item.colLayout || {  // 外部传了就用外部的
      xl: 6,
      lg: 6,
      md: 24,
      sm: 24,
      xs: 24
    }
  }))
);

// 表单dom
const formRef = ref();

// 表单双向绑定数据
const uiFormData = ref({});

// 监听外部 formData
watch(
  () => props.formData,
  (newValue) => {
    uiFormData.value = newValue;
    emit("update:formData", newValue);
  },
  { immediate: true, deep: true }
);

// 表单每一选项change事件
const formItemChange = (event, item) => {
  emit("handleFormItemChange", event, item);
};

// 表单校验
const validateForm = (callBack) => {
  formRef.value?.validate((valid, fields) => {
    if (valid) callBack(valid);
  });
};

defineExpose({ validateForm });
</script>

<style scoped lang="scss">
.ui-form {
  :deep(.el-form-item) {
    margin-bottom: 0;
  }

  .row {
    /* 网格行之间的间隔为 20px */
    row-gap: 20px;
  }
}
</style>
